//
// Created by mio on 25-5-19.
//

#include "AACDecoder.h"
#include "AudioResampler.h"

AACDecoder::AACDecoder(AVContext *ac, QObject *parent) : QThread(parent), avContext_(ac)
{
    audioResampler_.reset(new AudioResampler());
}

AACDecoder::~AACDecoder()
{
    Close();
}

int AACDecoder::Open(const AVCodecParameters *codecParamer)
{
    if (is_initial_ || !codecParamer) return -1;

    codec_ = (AVCodec*)avcodec_find_decoder(codecParamer->codec_id);
    if (!codec_) return -1;

    codecCtx_ = avcodec_alloc_context3(codec_);
    if (avcodec_parameters_to_context(codecCtx_, codecParamer) < 0) return -1;

    //设置属性，来去加速这个解码速度
    codecCtx_->flags |= AV_CODEC_FLAG2_FAST;

    if (avcodec_open2(codecCtx_, codec_, nullptr) != 0) return -1;

    // 初始化重采样
    // TODO: 搞清楚重采样的过程，即采集是什么格式，重采样输出后是什么格式，编码器输入的是什么格式，输出的又是什么格式
    avContext_->audio_channels_layout = AV_CH_LAYOUT_STEREO;
    avContext_->audio_fmt = AV_SAMPLE_FMT_S16;
    avContext_->audio_sample_rate = 44100;
    if (!audioResampler_->Open(codecCtx_->sample_rate, codecCtx_->channels, codecCtx_->sample_fmt,
                                44100, 2, AV_SAMPLE_FMT_S16))
    {
        return -1;
    }
    is_initial_ = true;
    start();
    return 0;
}

void AACDecoder::Close()
{
    quit_ = true;
    if (isRunning()) {
        this->quit();
        this->wait();
    }
}

void AACDecoder::run()
{
    int ret = -1;
    AVPacketPtr pkt;
    AVFramePtr outframe = nullptr;
    AVFramePtr pFrame = AVFramePtr(new AVFrame(), [](AVFrame *p) { av_frame_free(&p); }); // 解码帧
    while (!quit_ && audioResampler_)
    {
        if (!audio_queue_.size())
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            continue;
        }
        audio_queue_.pop(pkt);
        if (avcodec_send_packet(codecCtx_, pkt.get())) { break; } //如果不为0，error
        while (true)
        {
            ret = avcodec_receive_frame(codecCtx_, pFrame.get());
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; }
            else if (ret < 0) return;
            else
            {
                if (audioResampler_->Convert(pFrame, outframe)) {
                    if (outframe) { avContext_->audio_queue_.push(outframe); }
                }
            }
        }
    }

}
